/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#ifndef __S_LOCAL_H__
#define __S_LOCAL_H__


#include "../client/client.h"
#include "s_public.h"
#include "qal.h"


/*
 ==============================================================================

 SOUND MANAGER

 ==============================================================================
*/

#define MAX_SOUNDS						4096

typedef enum {
	SF_INTERNAL				= BIT(0),
	SF_NORESAMPLE			= BIT(1)
} soundFlags_t;

typedef struct sound_s {
	char					name[MAX_OSPATH];

	int						flags;

	int						rate;
	int						samples;
	int						length;
	int						size;
	byte *					data;

	uint					bufferId;

	struct sound_s *		nextHash;
} sound_t;

sound_t *			S_FindSound (const char *name, int flags);

void				S_InitSounds (void);
void				S_ShutdownSounds (void);

/*
 ==============================================================================

 SOUND SHADER MANAGER

 ==============================================================================
*/

#define MAX_SOUND_SHADERS				2048
#define MAX_SOUNDS_PER_SHADER			16

typedef enum {
	SSF_EXTERNAL			= BIT(0),
	SSF_DEFAULTED			= BIT(1),
	SSF_PRIVATE				= BIT(2),
	SSF_ANTIPRIVATE			= BIT(3),
	SSF_GLOBAL				= BIT(4),
	SSF_OMNIDIRECTIONAL		= BIT(5),
	SSF_LOOPING				= BIT(6),
	SSF_PLAYONCE			= BIT(7),
	SSF_NODUPS				= BIT(8),
	SSF_NOSTOP				= BIT(9),
	SSF_NOOFFSET			= BIT(10),
	SSF_NOOCCLUSION			= BIT(11),
	SSF_NOREVERB			= BIT(12)
} soundShaderFlags_t;

typedef enum {
	SP_BAD,
	SP_LOWEST,
	SP_LOW,
	SP_NORMAL,
	SP_HIGH,
	SP_HIGHEST
} soundPriority_t;

typedef struct soundShader_s {
	char					name[MAX_OSPATH];

	int						flags;

	soundPriority_t			priority;

	float					shakes;

	float					volume;
	float					pitch;

	float					minDistance;
	float					maxDistance;

	float					rolloffFactor;
	float					dopplerFactor;

	int						minSamples;

	int						numSounds;
	sound_t *				sounds[MAX_SOUNDS_PER_SHADER];

	struct soundShader_s *	nextHash;
} soundShader_t;

soundShader_t *		S_FindSoundShader (const char *name);

void				S_InitSoundShaders (void);
void				S_ShutdownSoundShaders (void);

/*
 ==============================================================================

 EFX MANAGER

 ==============================================================================
*/

#define MAX_REVERBS						BSP_MAX_AREAS

typedef struct {
	float					density;
	float					diffusion;

	float					gain;
	float					gainHF;
	float					gainLF;

	float					decayTime;
	float					decayHFRatio;
	float					decayLFRatio;
	bool					decayHFLimit;

	float					reflectionsGain;
	float					reflectionsDelay;
	odVec3					reflectionsPan;

	float					lateReverbGain;
	float					lateReverbDelay;
	odVec3					lateReverbPan;

	float					echoTime;
	float					echoDepth;

	float					modulationTime;
	float					modulationDepth;

	float					hfReference;
	float					lfReference;

	float					airAbsorptionGainHF;
	float					roomRolloffFactor;
} reverb_t;

typedef struct {
	bool					occlusion;
	bool					reverb;

	bool					reverbEditing;
	int						reverbEditingArea;

	reverb_t				reverbGeneric;
	reverb_t				reverbUnderwater;

	char					reverbName[MAX_OSPATH];
	reverb_t				reverbList[MAX_REVERBS];

	uint					directFilterId;
	uint					reverbFilterId;

	uint					effectId;
	uint					effectSlotId;
} efx_t;

void				S_EditCurrentReverb (void);

void				S_InitEFX (void);
void				S_ShutdownEFX (void);

/*
 ==============================================================================

 STREAMING MANAGER

 ==============================================================================
*/

void				S_UpdateStreaming (void);

void				S_InitStreaming (void);
void				S_ShutdownStreaming (void);

/*
 ==============================================================================

 EMITTER MANAGER

 ==============================================================================
*/

#define MAX_SOUND_EMITTERS				1024

typedef struct emitter_s {
	bool					active;
	int						index;

	int						listenerId;

	odVec3					position;
	odVec3					velocity;

	bool					underwater;
	int						area;

	struct emitter_s *		prev;
	struct emitter_s *		next;
} emitter_t;

void				S_InitEmitters (void);
void				S_ShutdownEmitters (void);

/*
 ==============================================================================

 LISTENER MANAGER

 ==============================================================================
*/

typedef struct {
	int						listenerId;
	int						time;

	odVec3					position;
	odVec3					velocity;
	float					orientation[6];

	bool					underwater;
	int						area;

	reverb_t *				reverb;
} listener_t;

void				S_UpdateListener (void);

/*
 ==============================================================================

 CHANNEL MANAGER

 ==============================================================================
*/

#define MAX_SOUND_CHANNELS				128

typedef struct {
	sound_t *				sound;				// If NULL, the channel is free

	int						listenerId;			// To allow overriding a specific sound
	int						channelId;			// To allow overriding a specific sound
	int						allocTime;			// To allow overriding oldest sounds

	soundShader_t *			soundShader;
	bool					local;
	emitter_t *				emitter;

	odVec3					position;
	odVec3					velocity;

	bool					underwater;
	int						area;

	uint					sourceId;
} channel_t;

channel_t *			S_PickChannel (int listenerId, int channelId, soundShader_t *soundShader, bool local, emitter_t *emitter);

void				S_PlayChannel (channel_t *channel);
void				S_StopChannel (channel_t *channel);
void				S_UpdateChannel (channel_t *channel);

void				S_InitChannels (void);
void				S_ShutdownChannels (void);

/*
 ==============================================================================

 INTERFACE

 ==============================================================================
*/

#define METERS_PER_UNIT					0.0381f

typedef struct {
	int						emitterUpdates;

	int						channels;

	int						portals;
} performanceCounters_t;

typedef struct {
	// Frame time in milliseconds
	int						frameTime;

	// System settings
	bool					active;

	// EFX
	efx_t					efx;

	// Listener
	listener_t				listener;

	// Channels
	int						numChannels;
	channel_t				channels[MAX_SOUND_CHANNELS];

	// Performance counters
	performanceCounters_t	pc;

	// Defaults
	sound_t *				defaultSound;

	soundShader_t *			defaultSoundShader;
} sndGlobals_t;

extern sndGlobals_t			snd;

extern alConfig_t			alConfig;

extern cvar_t *				s_logFile;
extern cvar_t *				s_singleSoundShader;
extern cvar_t *				s_singleEmitter;
extern cvar_t *				s_showUpdates;
extern cvar_t *				s_showEmitters;
extern cvar_t *				s_showChannels;
extern cvar_t *				s_showPortalChecks;
extern cvar_t *				s_skipStreaming;
extern cvar_t *				s_skipUpdates;
extern cvar_t *				s_skipEmitters;
extern cvar_t *				s_skipShakes;
extern cvar_t *				s_skipAttenuation;
extern cvar_t *				s_skipOcclusion;
extern cvar_t *				s_skipReverb;
extern cvar_t *				s_alDriver;
extern cvar_t *				s_ignoreALErrors;
extern cvar_t *				s_deviceName;
extern cvar_t *				s_masterVolume;
extern cvar_t *				s_effectsVolume;
extern cvar_t *				s_musicVolume;
extern cvar_t *				s_dopplerFactor;
extern cvar_t *				s_efxOcclusion;
extern cvar_t *				s_efxReverb;
extern cvar_t *				s_maxChannels;
extern cvar_t *				s_maxSoundsPerShader;
extern cvar_t *				s_maxSampleRate;

bool				S_SoundIsOccluded (int area, float distance, float maxDistance, float *occludedDistance);

/*
 ==============================================================================

 IMPLEMENTATION SPECIFIC FUNCTIONS

 ==============================================================================
*/

#ifdef _WIN32

#define AL_DRIVER_OPENAL				"OpenAL32"

#define ALImp_Init						ALW_Init
#define ALImp_Shutdown					ALW_Shutdown

void				ALW_Init (void);
void				ALW_Shutdown (void);

#else

#error "ALImp not available for this platform"

#endif


#endif	// __S_LOCAL_H__
